package com.stm.bi.executor;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.stm.base.api.DictionaryRemoteService;
import com.stm.base.dto.vo.DictVO;
import com.stm.base.provider.DictionaryProvider;
import com.stm.bi.core.util.DateUtils;
import com.stm.bi.dto.cmd.ReportDimensionAdd;
import com.stm.bi.dto.cmd.ReportModelAdd;
import com.stm.bi.dto.cmd.ReportStandardAdd;
import com.stm.bi.dto.cmd.ReportSubjectAdd;
import com.stm.bi.dto.query.*;
import com.stm.bi.dto.vo.*;
import com.stm.bi.enums.DateType;
import com.stm.bi.model.DatatablePage;
import com.stm.bi.model.RowData;
import com.stm.bi.model.Title;
import com.stm.bi.repository.report.*;
import com.stm.bi.utils.PaginationUtils;
import com.stm.bi.utils.SubjectUtils;
import com.stm.framework.core.tookit.BeanToolkit;
import com.stm.framework.dto.Response;
import com.stm.framework.model.CustomizePage;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

import static com.stm.bi.constant.DictionaryConstants.DIMENSION_POOL;
import static com.stm.bi.constant.ReportConstants.COLUMN_MODE;
import static com.stm.bi.constant.ReportConstants.ROW_MODE;

/**
 * 报表模型-查询执行器
 *
 * @author zhouyuanpeng
 * @date 2025-05-22
 */
@Component
public class ReportModelQueryExe {
    @Resource
    private ReportModelRepository reportModelRepository;
    @Resource
    private SubjectRepository subjectRepository;

    @Resource
    private ReportDimensionRepository reportDimensionRepository;

    @Resource
    private ReportSubjectRepository reportSubjectRepository;
    @Autowired
    private ReportStandardRepository reportStandardRepository;

    @Resource
    private DictionaryProvider dictionaryProvider;

    @Resource
    private DictionaryRemoteService dictionaryRemoteService;

    /**
     * 查询一条数据
     *
     * @param id
     */
    public Response<ReportModelVO> selectById(Long id) {
        ReportModelVO reportModel = reportModelRepository.selectById(id);
        if (reportModel == null) {
            return Response.failure("未找到该数据");
        }
        List<ReportDimensionVO> reportDimensionList = reportDimensionRepository.selectList(new ReportDimensionListQry().setModelId(reportModel.getId()));
        reportModel.setDimensions(reportDimensionList);

        List<ReportStandardVO> reportStandardList = reportStandardRepository.selectList(new ReportStandardListQry().setModelId(reportModel.getId()));
        reportModel.setStandards(reportStandardList);
        if (!reportStandardList.isEmpty()) {
            reportStandardList.get(0).setPreview(true);
        }

        List<ReportSubjectVO> reportSubjectList = reportSubjectRepository.selectList(new ReportSubjectListQry().setModelId(reportModel.getId()));
        Map<Long, List<ReportSubjectVO>> standardSubjectMap = reportSubjectList.stream().collect(Collectors.groupingBy(ReportSubjectVO::getStandardId));
        for (ReportStandardVO reportStandard : reportStandardList) {
            reportStandard.setSubjects(standardSubjectMap.get(reportStandard.getId()));
        }

        return Response.of(reportModel);
    }

    /**
     * 查询页面
     *
     * @param reportModelPageQry
     */
    public Response<CustomizePage<ReportModelVO>> selectPage(ReportModelPageQry reportModelPageQry) {
        List<ReportModelVO> reportModelVOS = reportModelRepository.selectList(reportModelPageQry);
        Set<Long> idList = reportModelVOS.stream().map(ReportModelVO::getId).collect(Collectors.toSet());

        List<ReportDimensionVO> reportDimensionVOS = reportDimensionRepository.selectList(new ReportDimensionListQry().setModelIds(idList));
        List<ReportSubjectVO> reportSubjectVOS = reportSubjectRepository.selectList(new ReportSubjectListQry().setModelIds(idList));
        Map<Long, List<ReportDimensionVO>> reportDimensionMap = reportDimensionVOS.stream().collect(Collectors.groupingBy(ReportDimensionVO::getModelId));
        Map<Long, List<ReportSubjectVO>> reportSubjectMap = reportSubjectVOS.stream().collect(Collectors.groupingBy(ReportSubjectVO::getModelId));


        List<DictVO> dictVOS = dictionaryRemoteService.selectList(DIMENSION_POOL).get();
        Map<String, String> dictMap = dictVOS.stream().collect(Collectors.toMap(DictVO::getValue, DictVO::getLabel));

        for (ReportModelVO reportModelVO : reportModelVOS) {
            List<ReportDimensionVO> reportDimensionVOSByModelId = reportDimensionMap.get(reportModelVO.getId());
            if (reportDimensionVOSByModelId != null) {
                reportDimensionVOSByModelId.forEach(reportDimensionVO -> {
                    String type = reportDimensionVO.getType();
                    reportDimensionVO.setType(dictMap.get(type));
                });

                reportModelVO.setReportDimension(reportDimensionVOSByModelId.stream().map(ReportDimensionVO::getType).distinct().collect(Collectors.joining(";")));
            }
            List<ReportSubjectVO> reportSubjectVOSByModelId = reportSubjectMap.get(reportModelVO.getId());
            if (reportSubjectVOSByModelId != null) {
                Set<String> subjectName = reportSubjectVOSByModelId.stream().map(ReportSubjectVO::getSubjectName).collect(Collectors.toSet());
                reportModelVO.setReportSubject(String.join(";", subjectName));
            }
        }

        Set<String> subjects = reportModelPageQry.getSubjects();
        if (subjects != null && !subjects.isEmpty()) {
            reportModelVOS = reportModelVOS.stream()
                    .filter(Objects::nonNull)
                    .filter(reportModelVO -> {
                        String reportSubject = reportModelVO.getReportSubject();
                        if (reportSubject == null || reportSubject.isEmpty()) {
                            return false;
                        }
                        return Arrays.stream(reportSubject.split(";"))
                                .anyMatch(subjects::contains);
                    })
                    .collect(Collectors.toList());
        }

        if (reportModelPageQry.getKeyword() != null && !reportModelPageQry.getKeyword().isEmpty()) {
            String filterName = reportModelPageQry.getKeyword();
            reportModelVOS = reportModelVOS.stream()
                    .filter(reportModelVO -> {
                        String modelName = reportModelVO.getName();
                        String reportSubject = reportModelVO.getReportSubject();

                        return (modelName != null && modelName.contains(filterName)) ||
                                (reportSubject != null && reportSubject.contains(filterName));
                    })
                    .collect(Collectors.toList());
        }

        CustomizePage<ReportModelVO> pagedResult = PaginationUtils.manualPaginate(reportModelVOS, reportModelPageQry.getPageSize(), reportModelPageQry.getPageNum());


        return Response.of(pagedResult);
    }

    /**
     * 查询列表
     *
     * @param reportModelListQry
     */
    public Response<List<ReportModelVO>> selectList(ReportModelListQry reportModelListQry) {
        return Response.of(reportModelRepository.selectList(reportModelListQry));
    }

    /**
     * 查询随机数据
     *
     * @param modelId
     * @param standardId
     */
    public Response<DatatablePage> selectRandomTable(Long modelId, Long standardId, Boolean showData) {

        //替换为报表模型查询方法
        ReportModelVO model = reportModelRepository.selectById(modelId);
        if(model == null){
            return Response.failure("未找到该数据");
        }
        String dimensionMode = model.getDimensionMode();
        List<ReportDimensionVO> dimensions = reportDimensionRepository.selectList(new ReportDimensionListQry().setModelId(modelId));
        List<ReportSubjectVO> reportSubjects = reportSubjectRepository.selectList(new ReportSubjectListQry()
                .setModelId(modelId)
                .setStandardId(standardId));

        //为了兼容在model创建时的表结构预览方法，这里转化为add对象
        List<ReportDimensionAdd> dimensionAdds = BeanToolkit.instance().copyList(dimensions, ReportDimensionAdd.class);
        List<ReportSubjectAdd> subjectAdds = BeanToolkit.instance().copyList(reportSubjects, ReportSubjectAdd.class);

        //排序
        dimensionAdds.sort(Comparator.comparingInt(ReportDimensionAdd::getIdx));
        //分离行列维度
        List<ReportDimensionAdd> rowDims = dimensionAdds.stream()
                .filter(d -> ROW_MODE.equals(d.getMode()))
                .toList();
        List<ReportDimensionAdd> columnDims = dimensionAdds.stream()
                .filter(d -> COLUMN_MODE.equals(d.getMode()))
                .toList();

        Integer num = Integer.parseInt(model.getDimensionNum());

        //一般情况下我们认为
        //列模式的科目纵向分布在列中
        //行模式的科目横向分布在行中
        //但是表格为一维时，实际的科目分布会反转
        //后续的数据生成逻辑主要以科目的横向分布与纵向分布为标准进行不同的逻辑处理
        boolean isInRow = num != 1 ? Objects.equals(ROW_MODE, dimensionMode) : Objects.equals(COLUMN_MODE, dimensionMode);

        //生成外层表体，这里运用到迭代后的方法
        DatatablePage table = reportPreview(rowDims, columnDims, subjectAdds, isInRow);

        if(!showData){
            return Response.of(table);
        }
        List<Title> titles = table.getTitles();
        List<RowData> rows = table.getDatas();

        //表体位空直接返回
        if (rows.isEmpty()) {
            return Response.of(table);
        }

        List<String> titleCodes = new ArrayList<>();
        getChildrenTitleCodes(titleCodes, titles);

        List<SubjectVO> subjects = subjectRepository.selectList(new SubjectListQry());
        if (subjects.isEmpty()) {
            return Response.of(table);
        }

        //赋值前，前N列标题不需要赋值，N为列维度数量
        for (int i = 0; i < columnDims.size(); i++) {
            titleCodes.removeFirst();
        }

        //获取科目code与科目对象映射
        Map<String, SubjectVO> codeMap = getCodeSubjectMap(num, subjects, rows, titleCodes, isInRow);

        if (isInRow) {
            for (RowData row : rows) {
                for (String code : titleCodes) {
                    row.put(code, SubjectUtils.getDiyReportRandomValue(codeMap.get(code)));
                }
            }
            //科目纵向排列,需要去除科目列
        } else {
            titleCodes.removeFirst();
            for (RowData row : rows) {
                SubjectVO subject = codeMap.get(row.get("subjectCode"));
                for (String code : titleCodes) {
                    row.put(code, SubjectUtils.getDiyReportRandomValue(subject));
                }
            }
        }

        table.setDatas(rows);
        return Response.of(table);
    }


    private void getChildrenTitleCodes(List<String> titleCodes, List<Title> titles) {
        for (Title title : titles) {
            if (title.getChildren() == null || ((List<Title>) title.getChildren()).isEmpty()) {
                titleCodes.add(title.getCode());
            } else {
                getChildrenTitleCodes(titleCodes, (List<Title>) title.getChildren());
            }
        }
    }

    private Map<String, SubjectVO> getCodeSubjectMap(Integer dimensionNum,
                                                     List<SubjectVO> subjects,
                                                     List<RowData> rows,
                                                     List<String> titleCodes,
                                                     Boolean isInRow) {

        Map<String, SubjectVO> codeMap = new HashMap<>();

        if(isInRow){
            for (String code : titleCodes) {
                //按照分隔符拆分
                String[] cs = code.split(":");
                if(cs.length < dimensionNum){
                    continue;
                }
                String c = cs[dimensionNum - 1];
                SubjectVO subject = subjects.stream()
                        .filter(s -> Objects.equals(s.getFieldName(), c))
                        .findAny().orElse(null);

                codeMap.put(code, subject);
            }
        }else {
            for(RowData row : rows){
                SubjectVO subject = subjects.stream()
                        .filter(s -> Objects.equals(s.getFieldName(), row.get("subjectCode")))
                        .findAny().orElse(null);

                codeMap.put((String) row.get("subjectCode"), subject);
            }
        }


        return codeMap;
    }

    /**
     * 报表模型预览
     *
     * @param reportModel
     */
    public Response<DatatablePage> reportPreview(ReportModelAdd reportModel) {

        // 筛选需要预览的科目
        ReportStandardAdd reportStandard = reportModel.getStandards().stream().filter(ReportStandardAdd::getPreview).findFirst().orElse(null);
        if(reportStandard == null){
            return Response.of(new DatatablePage<>());
        }
        List<ReportSubjectAdd> subjects = reportStandard.getSubjects();
        return Response.of(reportPreview(reportModel.getDimensions(), subjects, reportModel.getDimensionNum(), reportModel.getDimensionMode()));
    }

    /**
     * 报表模型预览
     */
    public DatatablePage reportPreview(List<ReportDimensionAdd> dimensions,
                                       List<ReportSubjectAdd> subjects,
                                       String dimensionNum,
                                       String dimensionMode) {
        DatatablePage vo = new DatatablePage();

        // 准备数据
        List<DictVO> dicts = dictionaryProvider.selectList(DIMENSION_POOL);
        DimensionGroups dimensionGroups = groupDimensions(dimensions);

        // 构建表头和数据
        vo.setTitles(buildTitles(dimensionNum,dimensionMode, dimensionGroups, dicts, subjects));
        vo.setDatas(buildRowData(dimensionNum,dimensionMode, dimensionGroups, dicts, subjects));

        return vo;
    }

    /**
     * 分组维度数据
     */
    private DimensionGroups groupDimensions(List<ReportDimensionAdd> dimensions) {
        /*List<ReportDimensionAdd> sortedDims = dimensions.stream()
                .sorted(Comparator.comparing(ReportDimensionAdd::getIdx))
                .collect(Collectors.toList());*/

        return new DimensionGroups(
                dimensions.stream().filter(d -> COLUMN_MODE.equals(d.getMode())).collect(Collectors.toList()),
                dimensions.stream().filter(d -> ROW_MODE.equals(d.getMode())).collect(Collectors.toList())
        );
    }

    /**
     * 构建报表模型表头
     */
    private List<Title> buildTitles(String num,
                                    String dimensionMode,
                                    DimensionGroups dimensionGroups,
                                    List<DictVO> dicts,
                                    List<ReportSubjectAdd> subjects) {
        if (subjects == null) {
            return Collections.emptyList();
        }

        List<Title> titles = new ArrayList<>();
        int dimensionNum = Integer.parseInt(num);

        // 添加行维度标题
        addRowDimensionTitles(titles, dimensionGroups.rowDims(), dicts);

        // 处理科目标题
        if (shouldAddSubjectTitle(dimensionNum, dimensionMode)) {
            titles.add(new Title().setCode("subjectName").setName("科目"));
        }

        // 根据维度数量构建不同的标题结构
        switch (dimensionNum) {
            case 1:
                handleOneDimensionTitles(titles, dimensionGroups, dicts, subjects, dimensionMode);
                break;
            case 2:
                handleTwoDimensionTitles(titles, dimensionGroups, dicts, subjects, dimensionMode);
                break;
            case 3:
                handleThreeDimensionTitles(titles, dimensionGroups, dicts, subjects, dimensionMode);
                break;
        }

        return titles;
    }

    /**
     * 添加行维度标题
     */
    private void addRowDimensionTitles(List<Title> titles, List<ReportDimensionAdd> rowDims, List<DictVO> dicts) {
        for (ReportDimensionAdd rowDim : rowDims) {
            dicts.stream()
                    .filter(e -> e.getValue().equals(rowDim.getType()))
                    .findFirst()
                    .ifPresent(e -> titles.add(new Title()
                            .setName(e.getLabel())
                            .setCode(rowDim.getType())));
        }
    }

    /**
     * 判断是否需要添加科目标题
     */
    private boolean shouldAddSubjectTitle(int dimensionNum, String dimensionMode) {
        return (dimensionNum == 1 && ROW_MODE.equals(dimensionMode)) ||
                (dimensionNum > 1 && COLUMN_MODE.equals(dimensionMode));
    }

    /**
     * 处理一维表头
     */
    private void handleOneDimensionTitles(List<Title> titles,
                                          DimensionGroups dimensionGroups,
                                          List<DictVO> dicts,
                                          List<ReportSubjectAdd> subjects,
                                          String dimensionMode) {
        if (ROW_MODE.equals(dimensionMode)) {
            buildColumnDimensionTitles(titles, dimensionGroups.columnDims().get(0), dicts, null, 0);
        } else {
            addSubjectTitles(titles, subjects);
        }
    }

    /**
     * 处理二维表头
     */
    private void handleTwoDimensionTitles(List<Title> titles,
                                          DimensionGroups dimensionGroups,
                                          List<DictVO> dicts,
                                          List<ReportSubjectAdd> subjects,
                                          String dimensionMode) {
        if (ROW_MODE.equals(dimensionMode)) {
            List<Title> childrenTitles = new ArrayList<>();
            buildColumnDimensionTitles(childrenTitles, dimensionGroups.columnDims().get(0), dicts, null, 1);

            // 嵌套科目
            for (Title childrenTitle : childrenTitles) {
                List<Title> childTitles = new ArrayList<>();
                addSubjectTitles(childTitles, subjects);
                childrenTitle.setChildren(childTitles);
            }
            titles.addAll(childrenTitles);
        } else {
            buildColumnDimensionTitles(titles, dimensionGroups.columnDims().get(0), dicts, null, 0);
        }
    }

    /**
     * 处理三维表头
     */
    private void handleThreeDimensionTitles(List<Title> titles,
                                            DimensionGroups dimensionGroups,
                                            List<DictVO> dicts,
                                            List<ReportSubjectAdd> subjects,
                                            String dimensionMode) {
        if (ROW_MODE.equals(dimensionMode)) {
            List<Title> childrenTitles = new ArrayList<>();
            buildColumnDimensionTitles(childrenTitles, dimensionGroups.columnDims().get(0), dicts, null, 0);

            List<Title> childTitles = new ArrayList<>();
            buildColumnDimensionTitles(childTitles, dimensionGroups.columnDims().get(1), dicts, null, 0);

            // 嵌套科目
            for (Title childrenTitle : childrenTitles) {
                List<Title> childTitles2 = new ArrayList<>();
                for (Title childTitle : childTitles) {
                    List<Title> childChildTitles = new ArrayList<>();
                    addSubjectTitles(childChildTitles, subjects);
                    childTitle.setChildren(childChildTitles);
                    childTitles2.add(childTitle);
                }
                childrenTitle.setChildren(childTitles2);
            }
            titles.addAll(childrenTitles);
        } else {
            buildColumnDimensionTitles(titles, dimensionGroups.columnDims().get(0), dicts, null, 0);
        }
    }

    /**
     * 添加科目标题
     */
    private void addSubjectTitles(List<Title> titles, List<ReportSubjectAdd> subjects) {
        for (ReportSubjectAdd subject : subjects) {
            titles.add(new Title()
                    .setCode(subject.getFieldName())
                    .setName(subject.getSubjectName())
                    .setSubName(subject.getParamName()));
        }
    }

    /**
     * 构建列维度标题
     */
    private void buildColumnDimensionTitles(List<Title> titles,
                                            ReportDimensionAdd columnDim,
                                            List<DictVO> dicts,
                                            List<Title> parentTitles,
                                            int level) {
        dicts.stream()
                .filter(e -> e.getValue().equals(columnDim.getType()))
                .findFirst()
                .ifPresent(e -> buildChildrenTitles(titles, null, level, e, columnDim.getParams(), parentTitles, columnDim.getType()));
    }

    /**
     * 构建报表模型数据
     */
    private List<RowData> buildRowData(String num,
                                       String dimensionMode,
                                       DimensionGroups dimensionGroups,
                                       List<DictVO> dicts,
                                       List<ReportSubjectAdd> subjects) {
        if (subjects == null) {
            return Collections.emptyList();
        }

        int dimensionNum = Integer.parseInt(num);
        List<RowData> data = new ArrayList<>();

        switch (dimensionNum) {
            case 1:
                handleOneDimensionData(data, dimensionGroups, dicts, subjects, dimensionMode);
                break;
            case 2:
                handleTwoDimensionData(data, dimensionGroups, dicts, subjects, dimensionMode);
                break;
            case 3:
                handleThreeDimensionData(data, dimensionGroups, dicts, subjects, dimensionMode);
                break;
        }

        return data;
    }

    /**
     * 处理一维数据
     */
    private void handleOneDimensionData(List<RowData> data,
                                        DimensionGroups dimensionGroups,
                                        List<DictVO> dicts,
                                        List<ReportSubjectAdd> subjects,
                                        String dimensionMode) {
        if (ROW_MODE.equals(dimensionMode)) {
            addSubjectData(data, subjects);
        } else {
            buildRowDimensionData(data, dimensionGroups.rowDims().get(0), dicts, 1);
        }
    }

    /**
     * 处理二维数据
     */
    private void handleTwoDimensionData(List<RowData> data,
                                        DimensionGroups dimensionGroups,
                                        List<DictVO> dicts,
                                        List<ReportSubjectAdd> subjects,
                                        String dimensionMode) {
        buildRowDimensionData(data, dimensionGroups.rowDims().get(0), dicts,
                ROW_MODE.equals(dimensionMode) ? 1 : subjects.size());

        if (COLUMN_MODE.equals(dimensionMode)) {
            addSubjectDataToRows(data, subjects);
        }
    }

    /**
     * 处理三维数据
     */
    private void handleThreeDimensionData(List<RowData> data,
                                          DimensionGroups dimensionGroups,
                                          List<DictVO> dicts,
                                          List<ReportSubjectAdd> subjects,
                                          String dimensionMode) {
        if (ROW_MODE.equals(dimensionMode)) {
            buildRowDimensionData(data, dimensionGroups.rowDims().get(0), dicts, 1);
        } else {
            handleComplexThreeDimensionData(data, dimensionGroups, dicts, subjects);
        }
    }

    /**
     * 处理复杂的三维数据(行模式)
     */
    private void handleComplexThreeDimensionData(List<RowData> data,
                                                 DimensionGroups dimensionGroups,
                                                 List<DictVO> dicts,
                                                 List<ReportSubjectAdd> subjects) {
        // 第一维度数据
        List<RowData> firstData = new ArrayList<>();
        buildRowDimensionData(firstData, dimensionGroups.rowDims().get(0), dicts, 1);
        int firstSize = firstData.size();



        // 第二维度数据
        List<RowData> secondData = new ArrayList<>();
        buildRowDimensionData(secondData, dimensionGroups.rowDims().get(1), dicts, 1);
        int secondSize = secondData.size();

        // 真 第一维度数据
        int thirdSize = secondSize * subjects.size();
        firstData.clear();
        buildRowDimensionData(firstData, dimensionGroups.rowDims().get(0), dicts, thirdSize);

        // 真 第二维度数据
        secondData.clear();
        buildRowDimensionData(secondData, dimensionGroups.rowDims().get(1), dicts, subjects.size());
        List<RowData> copy = new ArrayList<>(secondData);
        for (int i = 0; i < firstSize - 1; i++) {
            secondData.addAll(copy);
        }

        // 第三维度(科目)数据
        List<RowData> thirdData = generateSubjectData(subjects, firstSize * secondSize);

        // 合并数据
        data.addAll(mergeRowData(firstData, secondData, thirdData));
    }

    /**
     * 合并行数据
     */
    private List<RowData> mergeRowData(List<RowData> firstData,
                                       List<RowData> secondData,
                                       List<RowData> thirdData) {
        List<RowData> result = new ArrayList<>();
        for (int i = 0; i < firstData.size(); i++) {
            RowData merged = new RowData();
            merged.putAll(firstData.get(i));
            merged.putAll(secondData.get(i));
            merged.putAll(thirdData.get(i));
            result.add(merged);
        }
        return result;
    }

    /**
     * 生成科目数据
     */
    private List<RowData> generateSubjectData(List<ReportSubjectAdd> subjects, int repeatTimes) {
        List<RowData> result = new ArrayList<>();
        for (int i = 0; i < repeatTimes; i++) {
            for (ReportSubjectAdd subject : subjects) {
                RowData rowData = new RowData();
                rowData.put("subjectName", subject.getSubjectName());
                rowData.put("subjectCode",subject.getFieldName());
                rowData.put("subName", subject.getParamName());
                result.add(rowData);
            }
        }
        return result;
    }

    /**
     * 添加科目数据到行
     */
    private void addSubjectDataToRows(List<RowData> data, List<ReportSubjectAdd> subjects) {
        for (int i = 0; i < data.size(); i++) {
            ReportSubjectAdd subject = subjects.get(i % subjects.size());
            data.get(i).put("subjectName", subject.getSubjectName());
            data.get(i).put("subjectCode",subject.getFieldName());
            data.get(i).put("subName", subject.getParamName());
        }
    }

    /**
     * 添加科目数据
     */
    private void addSubjectData(List<RowData> data, List<ReportSubjectAdd> subjects) {
        for (ReportSubjectAdd subject : subjects) {
            RowData row = new RowData();
            row.put("subjectName", subject.getSubjectName());
            row.put("subjectCode",subject.getFieldName());
            row.put("subName", subject.getParamName());
            data.add(row);
        }
    }

    /**
     * 构建行维度数据
     */
    private void buildRowDimensionData(List<RowData> data,
                                       ReportDimensionAdd rowDim,
                                       List<DictVO> dicts,
                                       int subjectNum) {
        dicts.stream()
                .filter(e -> e.getValue().equals(rowDim.getType()))
                .findFirst()
                .ifPresent(e -> buildChildrenTitles(null, data, subjectNum, e, rowDim.getParams(),null, rowDim.getType()));
    }

    /**
     * 构建报表模型子表头或数据
     */
    public void buildChildrenTitles(List<Title> titles,
                                    List<RowData> data,
                                    int subjectNum,
                                    DictVO dict,
                                    String params,
                                    List<Title> parentTitles,
                                    String type) {
        String value = dict.getValue();
        List<DictVO> children = filterChildrenByParams(dict, params);

        if ("time".equals(value)) {
            handleTimeDimension(titles, data, subjectNum, params);
        } else if ("department".equals(value)) {
            handleDepartmentDimension(titles, data, subjectNum,type);
        } else {
            handleGenericDimension(titles, data, subjectNum, dict, children);
        }
    }

    /**
     * 根据参数过滤子维度
     */
    private List<DictVO> filterChildrenByParams(DictVO dict, String params) {
        if ("1".equals(dict.getRemark())) {
            String[] split = params.split(",");
            return dict.getChildren().stream()
                    .filter(e -> Arrays.asList(split).contains(e.getValue()))
                    .flatMap(e -> e.getChildren().stream())
                    .collect(Collectors.toList());
        }
        return dict.getChildren().stream()
                .filter(e -> e.getValue().equals(params))
                .flatMap(e -> e.getChildren().stream())
                .collect(Collectors.toList());
    }

    /**
     * 处理时间维度
     */
    private void handleTimeDimension(List<Title> titles,
                                     List<RowData> data,
                                     int subjectNum,
                                     String params) {
        LocalDate today = LocalDate.now();
        today = LocalDate.parse(today.getYear() + "-01-01");

        LocalDate firstDayOfMonth = today.with(TemporalAdjusters.firstDayOfMonth());
        LocalDate lastDayOfMonth = today.with(TemporalAdjusters.lastDayOfMonth());

        if (DateType.DAY.getValue().equals(params)) {
            handleDailyData(titles, data, subjectNum, firstDayOfMonth, lastDayOfMonth);
        } else if (DateType.WEEK.getValue().equals(params)) {
            handleWeeklyData(titles, data, subjectNum, firstDayOfMonth, lastDayOfMonth);
        } else if (DateType.MONTH.getValue().equals(params)) {
            handleMonthlyData(titles, data, subjectNum, today.getYear());
        } else if (DateType.YEAR.getValue().equals(params)) {
            handleYearlyData(titles, data, subjectNum);
        }
    }

    /**
     * 处理部门维度
     */
    private void handleDepartmentDimension(List<Title> titles,
                                           List<RowData> data,
                                           int subjectNum,
                                           String type) {
        List<String> depts = List.of("A", "B", "C", "D", "E");

        depts.forEach(dept -> {
            String code = "dept" + dept;
            String name = "部门" + dept;

            if (data == null) {
                titles.add(new Title().setCode(code).setName(name));
            } else {
                for (int j = 0; j < subjectNum; j++) {
                    RowData rowData = new RowData();
                    rowData.put("department", name);
                    data.add(rowData);
                }
            }
        });
    }

    /**
     * 处理通用维度
     */
    private void handleGenericDimension(List<Title> titles,
                                        List<RowData> data,
                                        int subjectNum,
                                        DictVO dict,
                                        List<DictVO> children) {
        for (DictVO child : children) {
            if (data == null) {
                titles.add(new Title().setCode(dict.getValue()).setName(child.getLabel()));
            } else {
                for (int j = 0; j < subjectNum; j++) {
                    RowData rowData = new RowData();
                    rowData.put(dict.getValue(), child.getLabel());
                    data.add(rowData);
                }
            }
        }
    }

    /**
     * 处理每日数据
     */
    private void handleDailyData(List<Title> titles,
                                 List<RowData> data,
                                 int subjectNum,
                                 LocalDate firstDayOfMonth,
                                 LocalDate lastDayOfMonth) {
        List<String> dateList = DateUtils.getDateList(firstDayOfMonth.toString(), lastDayOfMonth.toString(), DateType.DAY.getValue());
        dateList = dateList.subList(0, 5);

        for (String d : dateList) {
            String monthDay = d.substring(5);
            if (data == null) {
                titles.add(new Title().setCode(d).setName(monthDay));
            } else {
                for (int j = 0; j < subjectNum; j++) {
                    RowData rowData = new RowData();
                    rowData.put("time", monthDay);
                    data.add(rowData);
                }
            }
        }
    }

    /**
     * 处理每周数据
     */
    private void handleWeeklyData(List<Title> titles,
                                  List<RowData> data,
                                  int subjectNum,
                                  LocalDate firstDayOfMonth,
                                  LocalDate lastDayOfMonth) {
        List<String> weeklyRanges = getWeeklyRanges(firstDayOfMonth, lastDayOfMonth);

        for (String weeklyRange : weeklyRanges) {
            if (data == null) {
                titles.add(new Title().setCode(weeklyRange).setName(weeklyRange));
            } else {
                for (int j = 0; j < subjectNum; j++) {
                    RowData rowData = new RowData();
                    rowData.put("time", weeklyRange);
                    data.add(rowData);
                }
            }
        }
    }

    /**
     * 处理每月数据
     */
    private void handleMonthlyData(List<Title> titles,
                                   List<RowData> data,
                                   int subjectNum,
                                   int year) {
        for (int i = 1; i <= 5; i++) {
            String code = year + "-" + i;
            if (data == null) {
                titles.add(new Title().setCode(code).setName(i + ""));
            } else {
                for (int j = 0; j < subjectNum; j++) {
                    RowData rowData = new RowData();
                    rowData.put("time", i + "");
                    data.add(rowData);
                }
            }
        }
    }

    /**
     * 处理每年数据
     */
    private void handleYearlyData(List<Title> titles,
                                  List<RowData> data,
                                  int subjectNum) {
        for (int i = 0; i < 3; i++) {
            int year = 2023 + i;
            if (data == null) {
                titles.add(new Title().setCode(year + "").setName(year + ""));
            } else {
                for (int j = 0; j < subjectNum; j++) {
                    RowData rowData = new RowData();
                    rowData.put("time", year + "");
                    data.add(rowData);
                }
            }
        }
    }

    /**
     * 获取周度列表
     */
    public static List<String> getWeeklyRanges(LocalDate startDate, LocalDate endDate) {
        List<String> result = new ArrayList<>();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM.dd");

        LocalDate current = startDate;
        int weekNumber = 1;

        while (!current.isAfter(endDate)) {
            LocalDate weekStart = current;
            LocalDate weekEnd = weekStart.with(DayOfWeek.SUNDAY);

            if (weekEnd.isAfter(endDate)) {
                weekEnd = endDate;
            }

            result.add(String.format("第%d周 %s-%s",
                    weekNumber,
                    weekStart.format(formatter),
                    weekEnd.format(formatter)));

            current = weekEnd.plusDays(1);
            weekNumber++;
        }

        return result;
    }

    /**
     * 维度分组记录
     */
    private record DimensionGroups(List<ReportDimensionAdd> rowDims,
                                   List<ReportDimensionAdd> columnDims) {
    }

    /**
     * 报表模型预览
     *
     */
    public DatatablePage reportPreview(List<ReportDimensionAdd> rowDims,
                                       List<ReportDimensionAdd> columnDims,
                                       List<ReportSubjectAdd> subjects,
                                       Boolean isInRow) {
        // 字典数据准备
        List<DictVO> dicts = dictionaryProvider.selectList(DIMENSION_POOL);
        Map<Long, Map<String, String>> rowDimMap = getDimensionMap(rowDims, dicts);
        Map<Long, Map<String, String>> colDimMap = getDimensionMap(columnDims, dicts);

        List<Title> titles = new ArrayList<>();

        int level = 0;
        List<Title> columnTitles = getColumnTitles(columnDims, rowDims, dicts, isInRow);
        List<Title> dimensionTitles = getDimensionTitles(null, rowDims, subjects, rowDimMap, level, isInRow);
        titles.addAll(columnTitles);
        titles.addAll(dimensionTitles);

        List<RowData> data = new ArrayList<>();
        setRowData(data, null, columnDims, subjects, colDimMap, level, columnTitles.size(), isInRow);

        return new DatatablePage().setDatas(data).setTitles(titles);
    }

    private Map<Long, Map<String, String>> getDimensionMap(List<ReportDimensionAdd> dimensions,
                                                           List<DictVO> dicts){

        Map<Long, Map<String, String>> dimensionMap = new LinkedHashMap<>();
        if(dimensions.isEmpty()){
            return dimensionMap;
        }

        //处理所有维度对应需要展开的子项
        for(ReportDimensionAdd dimension: dimensions){
            String type = dimension.getType();
            String params = dimension.getParams();
            Map<String, String> map = new LinkedHashMap<>();

            DictVO dimensionDict = dicts.stream()
                    .filter(d -> Objects.equals(d.getValue(), type))
                    .findAny().orElse(new DictVO());

            //利用备注的0与1区分单选维度与多选维度,多选维度为1
            if(Objects.equals(dimensionDict.getRemark(), "1")){
                String[] codes = params.split(",");
                for(String code: codes){
                    map.put(code, dimensionDict.getChildren().stream()
                            .filter(d -> Objects.equals(d.getValue(), code))
                            .findAny().orElse(new DictVO()).getLabel());
                }
            }else {
                DictVO paramDict = dimensionDict.getChildren().stream()
                        .filter(d -> Objects.equals(d.getValue(), params))
                        .findAny().orElse(new DictVO());
                if(paramDict.getChildren() != null){
                    paramDict.getChildren()
                            .forEach(d -> map.put(d.getValue(), d.getLabel()));
                }
            }
            dimensionMap.put(dimension.getId(), map);
        }

        return dimensionMap;
    }

    private List<Title> getColumnTitles(List<ReportDimensionAdd> colDimensions,
                                        List<ReportDimensionAdd> rowDimensions,
                                        List<DictVO> dicts,
                                        Boolean isInRow) {
        List<Title> titles = new ArrayList<>();

        for(ReportDimensionAdd dimension: colDimensions){
            String type = dimension.getType();
            DictVO dict = dicts.stream()
                    .filter(d -> Objects.equals(d.getValue(), type))
                    .findAny().orElse(new DictVO());
            Title title = new Title().setName(dict.getLabel()).setCode(dimension.getType());
            titles.add(title);
        }

        if(rowDimensions.isEmpty()){
            return titles;
        }

        //科目在列中
        if(!isInRow){
            Title title = new Title().setName("科目").setCode("subjectName");
            titles.add(title);
        }

        return titles;
    }

    private List<Title> getDimensionTitles(String parenCode,
                                           List<ReportDimensionAdd> rowDims,
                                           List<ReportSubjectAdd> subjects,
                                           Map<Long, Map<String, String>> dimensionMap,
                                           Integer level,
                                           Boolean isInRow) {
        //科目在title中(科目在行中) 且 报表为行模式且维度循环已经结束
        if(level == rowDims.size() && isInRow){
            return getSubjectTitles(subjects, parenCode);
        }

        //循环层数大于等于维度数,直接返回空数组
        if(level >= rowDims.size()){
            return new ArrayList<>();
        }

        //获取对应维度与维度下展开的选项
        ReportDimensionAdd dimension = rowDims.get(level);
        Map<String, String> map = dimensionMap.get(dimension.getId());

        List<Title> thisTitles = getNormalTitles(map, parenCode);

        //循环标题处理子标题,递归调用
        for(Title title: thisTitles){
            List<Title> children = getDimensionTitles(title.getCode(), rowDims, subjects, dimensionMap, level + 1, isInRow);
            if(!children.isEmpty()){
                title.setChildren(children);
            }
        }

        return thisTitles;
    }

    /**
     * 科目标题处理
     */
    private List<Title> getSubjectTitles(List<ReportSubjectAdd> subjects, String parenCode){
        List<Title> titles = new ArrayList<>();
        for(ReportSubjectAdd subject: subjects){
            Title title = new Title();
            //parentCode不为空时,title的code赋值时要拼接parentCode
            String code = parenCode == null ? subject.getFieldName() : parenCode + ":" + subject.getFieldName();
            //如果有参数类型,则拼接参数类型
            code = subject.getParamType() == null ? code : code + ":" + subject.getParamType();
            title.setCode(code).setName(subject.getSubjectName());
            title.setSubName(subject.getParamName());
            titles.add(title);
        }
        return titles;
    }

    /**
     * 普通维度标题处理
     */
    private List<Title> getNormalTitles(Map<String, String> map, String parenCode){
        List<Title> titles = new ArrayList<>();
        map.forEach((k,v) -> {
            Title title = new Title();
            //parentCode不为空时,title的code赋值时要拼接parentCode
            String code = parenCode == null ? k : parenCode + ":" + k;
            title.setCode(code).setName(v);
            titles.add(title);
        });
        return titles;
    }

    private void setRowData(List<RowData> datas,
                            RowData row,
                            List<ReportDimensionAdd> colDims,
                            List<ReportSubjectAdd> subjects,
                            Map<Long, Map<String, String>> colDimMap,
                            Integer level,
                            Integer columnSize,
                            Boolean isInRow) {

        //当科目列分布时,且最终为最后一层循环
        if(level == colDims.size() && !isInRow){
            setSubjectRow(datas, row, subjects);
            return;
        }

        //当列数等于循环数,row构建已经完成,直接add并返回
        if(Objects.equals(columnSize, level)){
            datas.add(row);
            return;
        }

        //循环层数大于维度数,直接返回空
        if(level > colDims.size()){
            return;
        }

        //获取对应维度与维度下展开的选项
        ReportDimensionAdd dimension = colDims.get(level);
        Map<String, String> map = colDimMap.get(dimension.getId());

        for(Map.Entry<String, String> entry: map.entrySet()){
            RowData copy;
            if(row == null){
                copy = new RowData();
            }else {
                copy = new RowData(row);
            }
            copy.put(dimension.getType(), entry.getValue());
            setRowData(datas, copy, colDims, subjects, colDimMap, level + 1,  columnSize, isInRow);
        }
    }

    private void setSubjectRow(List<RowData> datas, RowData row, List<ReportSubjectAdd> subjects) {

        for(ReportSubjectAdd subject: subjects){
            RowData copy;
            if(row == null){
                copy = new RowData();
            }else {
                copy = new RowData(row);
            }
            copy.put("subjectName", subject.getSubjectName());
            copy.put("subjectCode",subject.getFieldName());
            copy.put("subName", subject.getParamName());
            datas.add(copy);
        }
    }

}
